package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.ProgressEvent;
	import flash.events.ServerSocketConnectEvent;
	import flash.net.ServerSocket;
	import flash.net.Socket;
	import flash.text.TextField;
	import flash.text.TextFieldType;
	import flash.utils.ByteArray;
	
	public class AirSocket extends Sprite
	{
		private var serverSocket:ServerSocket = new ServerSocket();
		private var clientSocket:Socket;
		
		private var localIP:TextField;
		private var localPort:TextField;
		private var logField:TextField;
		private var message:TextField;
		
		public function AirSocket()
		{
			setupUI();
		}
		
		private function onConnect( event:ServerSocketConnectEvent ):void
		{
			clientSocket = event.socket;
			clientSocket.addEventListener( ProgressEvent.SOCKET_DATA, onClientSocketData );
			log( "Connection from " + clientSocket.remoteAddress + ":" + clientSocket.remotePort );
		}
		
		private function onClientSocketData( event:ProgressEvent ):void
		{
			this.readData();
		}
		
		//是否读过头部
		private var isReadHead:Boolean = false;
		//消息长度
		private var msgLen:int = 0;
		
		//读取数据
		private function readData():void
		{
			while(clientSocket.bytesAvailable)
			{
				//如果还没读过头部则读一次。
				if (!isReadHead && clientSocket.bytesAvailable > 4)
				{
					var lenByte:ByteArray = new ByteArray();
					clientSocket.readBytes(lenByte, 0, 4);
					msgLen = lenByte.readInt();
					//trace("新的消息长度:" + this.msgLen);
					isReadHead = true;
				}
				//如果读了头部，并且当前可读长度大于等于消息长度，则开始读取
				if (isReadHead && clientSocket.bytesAvailable >= msgLen)
				{
					var objByte:ByteArray = new ByteArray();
					clientSocket.readBytes(objByte, 0, this.msgLen); 
					isReadHead = false;
					//解压缩，可以省略
					//objByte.uncompress();
					var obj:Object = objByte.readObject(); 
					readMsg(obj);   //读完了，可以去解释了，这里可以派发事件，比直接处理要快
				}
			}
		}
		
		private function readMsg(msg:*):void
		{
			log( "Received: " + msg.toString() );
		}
		
		private function bind( event:Event ):void
		{
			if( serverSocket.bound ) 
			{
				serverSocket.close();
				serverSocket = new ServerSocket();
				
			}
			serverSocket.bind( parseInt( localPort.text ), localIP.text );
			serverSocket.addEventListener( ServerSocketConnectEvent.CONNECT, onConnect );
			serverSocket.listen();
			log( "Bound to: " + serverSocket.localAddress + ":" + serverSocket.localPort );
		}
		
		private function send( event:Event ):void
		{
			try
			{
				if( clientSocket != null && clientSocket.connected )
				{
					clientSocket.writeUTFBytes( message.text );
					clientSocket.flush(); 
					log( "Sent message to " + clientSocket.remoteAddress + ":" + clientSocket.remotePort );
				}
				else log("No socket connection.");
			}
			catch ( error:Error )
			{
				log( error.message );
			}
		}
		
		private function log( text:String ):void
		{
			logField.appendText( text + "\n" );
			logField.scrollV = logField.maxScrollV;
			trace( text );
		}
		
		private function setupUI():void
		{
			localIP = createTextField( 10, 10, "Local IP", "127.0.0.1");
			localPort = createTextField( 10, 35, "Local port", "8098" );
			createTextButton( 170, 60, "Bind", bind );
			message = createTextField( 10, 85, "Message", "Lucy can't drink milk." );
			createTextButton( 170, 110, "Send", send );
			logField = createTextField( 10, 135, "Log", "", false, 200 )
			
			this.stage.nativeWindow.activate();
		}
		
		private function createTextField( x:int, y:int, label:String, defaultValue:String = '', editable:Boolean = true, height:int = 20 ):TextField
		{
			var labelField:TextField = new TextField();
			labelField.text = label;
			labelField.type = TextFieldType.DYNAMIC;
			labelField.width = 100;
			labelField.x = x;
			labelField.y = y;
			
			var input:TextField = new TextField();
			input.text = defaultValue;
			input.type = TextFieldType.INPUT;
			input.border = editable;
			input.selectable = editable;
			input.width = 280;
			input.height = height;
			input.x = x + labelField.width;
			input.y = y;
			
			this.addChild( labelField );
			this.addChild( input );
			
			return input;
		}
		
		private function createTextButton( x:int, y:int, label:String, clickHandler:Function ):TextField
		{
			var button:TextField = new TextField();
			button.htmlText = "<u><b>" + label + "</b></u>";
			button.type = TextFieldType.DYNAMIC;
			button.selectable = false;
			button.width = 180;
			button.x = x;
			button.y = y;
			button.addEventListener( MouseEvent.CLICK, clickHandler );
			
			this.addChild( button );
			return button;
		}        
	}
}